import React, { useState, useEffect, useRef } from 'react';
import style from './Liao.module.css';
import { useNavigate } from 'react-router-dom';
import TransferCard from './TransferCard';

// === 表情包分组结构 ===
const EMOJI_GROUPS = [
  {
    key: '收藏',
    name: '收藏',
    images: ['/emoji/收藏/1.jpg', '/emoji/收藏/2.jpg', '/emoji/收藏/3.jpg'],
  },
  {
    key: 'lan',
    name: '懒洋洋',
    images: ['/emoji/lan/1.gif', '/emoji/lan/2.gif', '/emoji/lan/3.gif', '/emoji/lan/4.gif', '/emoji/lan/5.gif', '/emoji/lan/6.gif', '/emoji/lan/7.gif'],
  },
  {
    key: 'zhuzhuxia',
    name: '猪猪侠',
    images: ['/emoji/zhuzhuxia/1.jpg', '/emoji/zhuzhuxia/2.jpg', '/emoji/zhuzhuxia/3.jpg'],
  },
  {
    key: 'naichashu',
    name: '奶茶鼠',
    images: ['/emoji/naichashu/1.webp', '/emoji/naichashu/2.webp', '/emoji/naichashu/3.webp', '/emoji/naichashu/4.webp', '/emoji/naichashu/5.webp', '/emoji/naichashu/6.webp', '/emoji/naichashu/7.webp', '/emoji/naichashu/8.webp', '/emoji/naichashu/9.webp', '/emoji/naichashu/10.webp', '/emoji/naichashu/11.webp', '/emoji/naichashu/12.webp'],
  },
  {
    key: 'zhang',
    name: '章鱼哥',
    images: ['/emoji/zhang/1jpg.jpg', '/emoji/zhang/2.jpg', '/emoji/zhang/3.jpg', '/emoji/zhang/4.jpg', '/emoji/zhang/5.jpg', '/emoji/zhang/6.jpg', '/emoji/zhang/7.jpg', '/emoji/zhang/8.jpg', '/emoji/zhang/9.jpg', '/emoji/zhang/10.jpg', '/emoji/zhang/11.jpg', '/emoji/zhang/12.jpg', '/emoji/zhang/13.jpg', '/emoji/zhang/14.jpg', '/emoji/zhang/15.jpg', '/emoji/zhang/16.jpg', '/emoji/zhang/17.jpg', '/emoji/zhang/18.jpg'],
  },
];

export default function Liao() {
    const navigate= useNavigate();
    // 初始化时从 localStorage 加载
    const [messages, setMessages] = useState(() => {
        try {
            const saved = localStorage.getItem('tliao_chat_messages');
            return saved ? JSON.parse(saved) : [];
        } catch {
            return [];
        }
    });
    // 自动保存到 localStorage
    useEffect(() => {
        try {
            localStorage.setItem('tliao_chat_messages', JSON.stringify(messages));
        } catch {}
    }, [messages]);
    const [inputMessage, setInputMessage] = useState('');
    const [isConnected, setIsConnected] = useState(false);
    const [ws, setWs] = useState(null);
    const [connectionError, setConnectionError] = useState('');
    const messagesEndRef = useRef(null);
    const [userId] = useState('user_002');
    const [targetUserId, setTargetUserId] = useState('user_001');
    const [isVoiceMode, setIsVoiceMode] = useState(false);
    const [showPlusPanel, setShowPlusPanel] = useState(false);
    const [isRecording, setIsRecording] = useState(false);
    const [recordTime, setRecordTime] = useState(0);
    const recordTimerRef = useRef(null);
    const recordTimeRef = useRef(0);
    // 语音已读状态
    const [voiceReadMap, setVoiceReadMap] = useState({}); // {msgId: true/false}
    // 录音音量动画
    const [volumeLevel, setVolumeLevel] = useState(1);
    const volumeTimerRef = useRef(null);
    // 录音相关
    const [mediaRecorder, setMediaRecorder] = useState(null);
    const [audioChunks, setAudioChunks] = useState([]);
    const [audioUrl, setAudioUrl] = useState('');
    const [playingAudioId, setPlayingAudioId] = useState(null);
    const [recordError, setRecordError] = useState('');
    const [audioMimeType, setAudioMimeType] = useState('audio/webm');
    const analyserRef = useRef(null);
    const animationRef = useRef(null);
    const [selectedFiles, setSelectedFiles] = useState([]);
    const fileInputRef = useRef(null);  
    const [showImagePicker, setShowImagePicker] = useState(false);
    const publicImages = [
      '/10.jpg', '/11.jpg', '/12.jpg', '/13.jpg', '/14.jpg', '/19.png', '/20.png',
      '/微信头像.jpg', '/个人头像.png', '/净化器.png', '/卡比龙总裁烟.png', '/咖啡机.png',
      '/手表.png', '/拉菲.jfif', '/无线充电器.png', '/无线耳机.png', '/洋酒.png', '/电脑.png',
      '/白酒.png', '/礼盒.png', '/红酒.png', '/配件.png', '/香烟.png'
    ];
    
    const [selectedPublicImages, setSelectedPublicImages] = useState([]);
    // 1. 预览相关状态
    const [previewImages, setPreviewImages] = useState([]); // 所有图片url
    const [previewIndex, setPreviewIndex] = useState(0);    // 当前预览索引
    const [previewTip, setPreviewTip] = useState('');
    const [showCallSheet, setShowCallSheet] = useState(false);
    const [showMoreMenu, setShowMoreMenu] = useState(false);

    // 选择模式相关状态
    const [isSelectMode, setIsSelectMode] = useState(false);
    const [selectedMessages, setSelectedMessages] = useState([]);

    // 收藏相关状态
    const [favoriteEmojis, setFavoriteEmojis] = useState(() => {
      try {
        const saved = localStorage.getItem('tliao_favorite_emojis');
        return saved ? JSON.parse(saved) : [];
      } catch {
        return [];
      }
    });
    // 收藏图片
    const handleCollectEmoji = (img) => {
      if (!favoriteEmojis.includes(img)) {
        const newFav = [img, ...favoriteEmojis];
        setFavoriteEmojis(newFav);
        localStorage.setItem('tliao_favorite_emojis', JSON.stringify(newFav));
      }
    };
    // 动态更新收藏分组内容
    const emojiGroupsWithFavorites = EMOJI_GROUPS.map(group => {
      if (group.key === '收藏') {
        return { ...group, images: favoriteEmojis };
      }
      return group;
    });

    // 关闭更多菜单的全局点击事件
    useEffect(() => {
      if (!showMoreMenu) return;
      const close = () => setShowMoreMenu(false);
      window.addEventListener('click', close);
      return () => window.removeEventListener('click', close);
    }, [showMoreMenu]);

    // 自动滚动到最新消息
    const scrollToBottom = () => {
        messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
    };

    useEffect(() => {
        scrollToBottom();
    }, [messages]);

    // WebSocket 连接
    useEffect(() => {
        // 这里使用一个模拟的WebSocket服务器地址，你需要替换为实际的服务器地址
        const wsUrl = 'ws://localhost:8080';
        console.log('尝试连接到:', wsUrl);
        
        const websocket = new WebSocket(wsUrl);

        websocket.onopen = () => {
            console.log('WebSocket连接已建立');
            setIsConnected(true);
            setConnectionError('');
            
            // 发送用户身份信息
            const authMessage = {
                type: 'auth',
                userId: userId,
                action: 'connect'
            };
            console.log('发送身份验证:', authMessage);
            websocket.send(JSON.stringify(authMessage));
        };

        websocket.onmessage = (event) => {
            console.log('收到消息:', event.data);
            try {
                const data = JSON.parse(event.data);
                
                switch (data.type) {
                    case 'message':
                        setMessages(prev => [...prev, {
                            id: Date.now(),
                            text: data.message,
                            sender: data.senderId,
                            timestamp: new Date().toLocaleTimeString(),
                            isOwn: data.senderId === userId
                        }]);
                        break;
                    case 'system':
                        setMessages(prev => [...prev, {
                            id: Date.now(),
                            text: data.message,
                            sender: 'system',
                            timestamp: new Date().toLocaleTimeString(),
                            isOwn: false
                        }]);
                        break;
                    case 'auth':
                        if (data.status === 'success') {
                            console.log('身份验证成功');
                            // 默认发送消息 
                            // 这个我可以用在 添加好友后 首次发送的消息
                            
                            // setMessages(prev => [...prev, {
                            //     id: Date.now(),
                            //     text: '干啥呢',
                            //     sender: 'system',
                            //     timestamp: new Date().toLocaleTimeString(),
                            //     isOwn: false
                            // }]);
                        }
                        break;
                    case 'voice':
                        // 处理语音消息
                        setMessages(prev => [...prev, {
                            id: data.msgId || Date.now(),
                            type: 'voice',
                            sender: data.senderId,
                            isOwn: data.senderId === userId,
                            duration: data.duration,
                            audioBase64: data.audioBase64,
                            timestamp: new Date().toLocaleTimeString()
                        }]);
                        break;
                    case 'transfer':
                        setMessages(prev => [...prev, {
                            id: data.msgId || Date.now(),
                            type: 'transfer',
                            sender: data.senderId,
                            isOwn: data.senderId === userId,
                            amount: data.amount,
                            remark: data.remark,
                            senderName: data.senderName,
                            receiverName: data.receiverName,
                            timestamp: new Date().toLocaleTimeString()
                        }]);
                        break;
                    case 'image':
                        setMessages(prev => [...prev, {
                            id: data.msgId || Date.now(),
                            type: 'image',
                            sender: data.senderId,
                            isOwn: data.senderId === userId,
                            fileUrl: data.fileUrl,
                            timestamp: new Date().toLocaleTimeString()
                        }]);
                        break;
                    default:
                        console.log('收到未知消息类型:', data);
                }
            } catch (error) {
                console.error('解析消息失败:', error);
            }
        };

        websocket.onclose = (event) => {
            console.log('WebSocket连接已关闭:', event.code, event.reason);
            setIsConnected(false);
            setConnectionError('连接已断开');
        };

        websocket.onerror = (error) => {
          
            setIsConnected(false);
            setConnectionError('连接失败，请检查服务器是否运行');
        };

        setWs(websocket);

        // 清理函数
        return () => {
            websocket.close();
        };
    }, [userId]);

    // 发送消息
    const sendMessage = () => {
        console.log('尝试发送消息...');
        console.log('输入消息:', inputMessage);
        console.log('连接状态:', isConnected);
        console.log('目标用户ID:', targetUserId);
        console.log('WebSocket对象:', ws);

        if (!inputMessage.trim()) {
            alert('请输入消息内容');
            return;
        }

        if (!isConnected) {
            alert('WebSocket未连接，请检查服务器是否运行');
            return;
        }



        if (!ws || ws.readyState !== WebSocket.OPEN) {
            alert('网络连接异常，请刷新页面重试');
            return;
        }

        const messageData = {
            type: 'message',
            message: inputMessage,
            senderId: userId,
            receiverId: targetUserId,
            timestamp: new Date().toISOString()
        };

        console.log('发送消息数据:', messageData);

        try {
            ws.send(JSON.stringify(messageData));
            console.log('消息发送成功');

            // 添加到本地消息列表
            setMessages(prev => [...prev, {
                id: Date.now(),
                text: inputMessage,
                sender: userId,
                timestamp: new Date().toLocaleTimeString(),
                isOwn: true
            }]);

            setInputMessage('');
        } catch (error) {
            console.error('发送消息失败:', error);
            alert('发送消息失败: ' + error.message);
        }
    };

    // 处理回车键发送
    const handleKeyPress = (e) => {
        if (e.key === 'Enter' && !e.shiftKey) {
            e.preventDefault();
            sendMessage();
        }
    };

    // 模拟接收消息（用于测试）
    const simulateReceiveMessage = () => {
        const mockMessage = {
            id: Date.now(),
            text: `这是来自 ${targetUserId || '其他用户'} 的模拟消息`,
            sender: targetUserId || 'other_user',
            timestamp: new Date().toLocaleTimeString(),
            isOwn: false
        };
        setMessages(prev => [...prev, mockMessage]);
    };

    // 清除所有消息
    const clearMessages = () => {
        setMessages([]);
        localStorage.removeItem('tliao_chat_messages');
    };

    // 切换选择模式
    const toggleSelectMode = () => {
        setIsSelectMode(!isSelectMode);
        setSelectedMessages([]);
    };

    // 选择/取消选择消息
    const toggleMessageSelection = (messageId) => {
        setSelectedMessages(prev => {
            const newSet = prev.includes(messageId) ? prev.filter(id => id !== messageId) : [...prev, messageId];
            return newSet;
        });
    };

    // 删除选中的消息
    const deleteSelectedMessages = () => {
        if (selectedMessages.length === 0) return;
        setMessages(prev => prev.filter(msg => !selectedMessages.includes(msg.id)));
        setSelectedMessages([]);
        setIsSelectMode(false);
    };

    // 全选/取消全选
    const toggleSelectAll = () => {
        if (selectedMessages.length === messages.length) {
            setSelectedMessages([]);
        } else {
            setSelectedMessages(messages.map(msg => msg.id));
        }
    };

    // 重新连接
    const reconnect = () => {
        if (ws) {
            ws.close();
        }
        setConnectionError('');
        // 重新连接会在useEffect中自动触发
    };

    // 播放语音气泡时详细提示
    const handleVoiceClick = (msg) => {
        if (!msg.isOwn && !voiceReadMap[msg.id]) {
            setVoiceReadMap(v => ({ ...v, [msg.id]: true }));
        }
        if (msg.audioBase64) {
            const mime = msg.mimeType || 'audio/webm';
            const audio = new window.Audio('data:' + mime + ';base64,' + msg.audioBase64);
            setPlayingAudioId(msg.id);
            audio.play().catch(e => {
                alert('音频播放失败: ' + e.message + '\n格式:' + mime + '\n请用最新版Chrome/Edge测试，或在控制台window.lastMessages查看base64。');
                console.error('音频播放失败', e, msg);
            });
            audio.onended = () => setPlayingAudioId(null);
        } else {
            alert('没有可播放的语音数据，请检查录音权限或浏览器兼容性。');
        }
    };

    // 空格键录音快捷键
    useEffect(() => {
        const handleKeyDown = (e) => {
            const active = document.activeElement;
            if ((e.code === 'Space' || e.keyCode === 32) && !isRecording && isVoiceMode && active.tagName !== 'INPUT' && active.tagName !== 'TEXTAREA') {
                e.preventDefault();
                handleVoiceBtnClick();
            }
        };
        const handleKeyUp = (e) => {
            if ((e.code === 'Space' || e.keyCode === 32) && isRecording) {
                e.preventDefault();
                handleVoiceBtnClick();
            }
        };
        window.addEventListener('keydown', handleKeyDown);
        window.addEventListener('keyup', handleKeyUp);
        return () => {
            window.removeEventListener('keydown', handleKeyDown);
            window.removeEventListener('keyup', handleKeyUp);
        };
    }, [isRecording, isVoiceMode]);

    // 便于调试
    useEffect(() => {
        window.lastMessages = messages;
    }, [messages]);

    const handleVoiceBtnClick = async () => {
        if (!isRecording) {
            // 开始录音
            if (navigator.mediaDevices && window.MediaRecorder) {
                const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
                let localChunks = [];
                const mr = new window.MediaRecorder(stream);
                mr.ondataavailable = e => localChunks.push(e.data);
                mr.onstop = () => {
                    // 1. 先清除定时器，确保recordTimeRef.current为最终时长
                    if (recordTimerRef.current) clearInterval(recordTimerRef.current);
                    setRecordTime(recordTimeRef.current);
                    const blob = new Blob(localChunks, { type: 'audio/webm' });
                    const url = URL.createObjectURL(blob);
                    setAudioUrl(url);

                    // 转 base64 并发送
                    const reader = new FileReader();
                    reader.onloadend = () => {
                        const base64data = reader.result.split(',')[1];
                        const duration = recordTimeRef.current || 1;
                        const voiceMsg = {
                            type: 'voice',
                            senderId: userId,
                            receiverId: targetUserId,
                            duration,
                            audioBase64: base64data,
                            msgId: Date.now(),
                            timestamp: new Date().toISOString()
                        };
                        ws && ws.readyState === 1 && ws.send(JSON.stringify(voiceMsg));
                        // 本地也显示气泡
                        setMessages(prev => [...prev, {
                            id: voiceMsg.msgId,
                            type: 'voice',
                            sender: userId,
                            isOwn: true,
                            duration: voiceMsg.duration,
                            audioBase64: base64data,
                            timestamp: new Date().toLocaleTimeString()
                        }]);
                    };
                    reader.readAsDataURL(blob);
                };
                mr.start();
                setMediaRecorder(mr);
                setIsRecording(true);

                // 音量分析
                const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
                const source = audioCtx.createMediaStreamSource(stream);
                const analyser = audioCtx.createAnalyser();
                analyser.fftSize = 256;
                source.connect(analyser);
                analyserRef.current = analyser;

                const dataArray = new Uint8Array(analyser.frequencyBinCount);
                const updateVolume = () => {
                    analyser.getByteTimeDomainData(dataArray);
                    const max = Math.max(...dataArray);
                    setVolumeLevel(Math.floor((max - 128) / 8) + 1);
                    animationRef.current = requestAnimationFrame(updateVolume);
                };
                updateVolume();

                // 录音时长定时器
                setRecordTime(0);
                recordTimeRef.current = 0;
                if (recordTimerRef.current) clearInterval(recordTimerRef.current);
                recordTimerRef.current = setInterval(() => {
                    setRecordTime(t => {
                        recordTimeRef.current = t + 1;
                        return t + 1;
                    });
                }, 1000);
            } else {
                alert('当前浏览器不支持录音');
            }
        } else {
            // 结束录音
            if (mediaRecorder) {
                mediaRecorder.stop();
                setMediaRecorder(null);
            }
            setIsRecording(false);
            if (animationRef.current) cancelAnimationFrame(animationRef.current);
            setVolumeLevel(1);
            // 录音结束时清除定时器
            if (recordTimerRef.current) clearInterval(recordTimerRef.current);
        }
    };

    const closeImagePicker = () => {
      setImagePickerVisible(false);
      setTimeout(() => setShowImagePicker(false), 300);
      setSelectedPublicImages([]);
    };

    // 选择模式相关函数
    const selectAllMessages = () => {
        setSelectedMessages(messages.map(msg => msg.id));
    };

    const deselectAllMessages = () => {
        setSelectedMessages([]);
    };

    const exitSelectMode = () => {
        setIsSelectMode(false);
        setSelectedMessages([]);
    };

    // 1. 状态和方法（如未有则补充）
    const [imagePickerVisible, setImagePickerVisible] = useState(false);
    const openImagePicker = () => {
      setShowImagePicker(true);
      setTimeout(() => setImagePickerVisible(true), 10);
    };

    // === 表情包面板相关状态 ===
    const [showEmojiPanel, setShowEmojiPanel] = useState(false);
    const [activeEmojiGroup, setActiveEmojiGroup] = useState('收藏');

    // 发送表情包图片或emoji
    const sendEmojiImage = (data) => {
      if (typeof data === 'string' && data.length <= 4) {
        // emoji
        const emojiMsg = {
          type: 'emoji',
          text: data,
          senderId: userId,
          receiverId: targetUserId,
          timestamp: new Date().toISOString()
        };
        ws && ws.readyState === 1 && ws.send(JSON.stringify(emojiMsg));
        setMessages(prev => [...prev, {
          id: Date.now() + Math.random(),
          type: 'emoji',
          sender: userId,
          isOwn: true,
          text: data,
          timestamp: new Date().toLocaleTimeString()
        }]);
      } else {
        // 图片
        const imgMsg = {
          type: 'image',
          fileUrl: data,
          senderId: userId,
          receiverId: targetUserId,
          timestamp: new Date().toISOString()
        };
        ws && ws.readyState === 1 && ws.send(JSON.stringify(imgMsg));
        setMessages(prev => [...prev, {
          id: Date.now() + Math.random(),
          type: 'image',
          sender: userId,
          isOwn: true,
          fileUrl: data,
          timestamp: new Date().toLocaleTimeString()
        }]);
      }
      setShowEmojiPanel(false);
    };

    // 语音转文字相关状态
    const [voiceTextMap, setVoiceTextMap] = useState({}); // {msgId: '转写内容'}
    const [voiceTextShowMap, setVoiceTextShowMap] = useState({}); // {msgId: true/false}
    const [voiceTranscribing, setVoiceTranscribing] = useState({}); // {msgId: true/false}

    return (
        <div className={style.chatContainer}>
            <div className={style.chatHeader}>
                <div className={style.headerTitleRow}>
                    <h2>懒得起名</h2>
                    <button
                        className={style.moreBtn}
                        title="更多"
                        onClick={e => {
                            e.stopPropagation();
                            setShowMoreMenu(true);
                        }}
                    >
                        <svg width="24" height="24" viewBox="0 0 24 24"><circle cx="5" cy="12" r="2" fill="#222"/><circle cx="12" cy="12" r="2" fill="#222"/><circle cx="19" cy="12" r="2" fill="#222"/></svg>
                    </button>
                </div>
                <div className={style.connectionStatus}>
                    <span className={`${style.statusDot} ${isConnected ? style.connected : style.disconnected}`}></span>
                    <span style={{ fontSize: '12px', color: '#666', marginLeft: '8px' }}>
                        💾 聊天记录已保存 ({messages.length} 条)
                    </span>
                    {connectionError && (
                        <span className={style.errorText}> - {connectionError}</span>
                    )}
                </div>
            </div>

            {/* 更多菜单弹窗 */}
            {showMoreMenu && (
                <div
                    style={{
                        position: 'fixed',
                        top: 56,
                        right: 20,
                        background: '#fff',
                        borderRadius: 8,
                        boxShadow: '0 2px 12px rgba(0,0,0,0.15)',
                        zIndex: 2000,
                        minWidth: 140,
                        padding: '8px 0'
                    }}
                    onClick={e => e.stopPropagation()}
                >
                    <div
                        style={{
                            padding: '10px 20px',
                            cursor: 'pointer',
                            color: '#222',
                            fontSize: 15
                        }}
                        onClick={() => {
                            setShowMoreMenu(false);
                            setIsSelectMode(true);
                        }}
                    >
                        删除选择记录
                    </div>
                    <div
                        style={{
                            padding: '10px 20px',
                            cursor: 'pointer',
                            color: '#ff3b30',
                            fontSize: 15
                        }}
                        onClick={() => {
                            setShowMoreMenu(false);
                            if (window.confirm('确定要全部删除吗？')) setMessages([]);
                        }}
                    >
                        全部删除
                    </div>
                </div>
            )}

           

            {/* <div className={style.userInfo}>
                <div className={style.userId}>
                    <label>我的ID: </label>
                    <span>{userId}</span>
                </div>
                <div className={style.targetUser}>
                    <label>目标用户ID: </label>
                    <span>{targetUserId}</span>
                </div>
            </div> */}

            <div className={style.messagesContainer}>
                {messages.length === 0 ? (
                    <div className={style.emptyState}>
                    
                    </div>
                ) : (
                    <>
                        {messages.map((message) => (
                            <div
                                key={message.id}
                                className={`${style.message} ${message.isOwn ? style.ownMessage : style.otherMessage}`}
                                style={isSelectMode ? { paddingLeft: '50px', position: 'relative' } : {}}
                            >
                                {/* 选择模式下的选择框 */}
                                {isSelectMode && (
                                    <div
                                        style={{
                                            position: 'absolute',
                                            left: 10,
                                            top: '50%',
                                            transform: 'translateY(-50%)',
                                            width: 20,
                                            height: 20,
                                            borderRadius: '50%',
                                            border: '2px solid #ddd',
                                            background: selectedMessages.includes(message.id) ? '#06c05f' : '#fff',
                                            display: 'flex',
                                            alignItems: 'center',
                                            justifyContent: 'center',
                                            cursor: 'pointer',
                                            zIndex: 10
                                        }}
                                        onClick={() => toggleMessageSelection(message.id)}
                                    >
                                        {selectedMessages.includes(message.id) && (
                                            <svg width="12" height="12" viewBox="0 0 12 12">
                                                <path d="M2 6l3 3 5-5" stroke="#fff" strokeWidth="2" fill="none"/>
                                            </svg>
                                        )}
                                    </div>
                                )}
                                <div className={style.messageRow}>
                                    {/* 左侧头像 */}
                                    {!message.isOwn && (
                                        <img src="/个人头像.png" alt="avatar" className={style.avatar} />
                                    )}
                                    <div className={style.bubbleWrap}>
                                        <div className={style.bubbleBox}>
                                            {!message.isOwn && <span className={style.bubbleArrowLeft}></span>}
                                            {message.type === 'voice' ? (
                                                <div
                                                    style={{
                                                        display: 'flex',
                                                        flexDirection: message.isOwn ? 'row-reverse' : 'row',
                                                        alignItems: 'center',
                                                        gap: 8,
                                                    }}
                                                >
                                                    <div
                                                        className={style.voiceBubble}
                                                        style={{ width: Math.min(60 + (message.duration || 1) * 8, 220) }}
                                                        onClick={() => !isSelectMode && handleVoiceClick(message)}
                                                    >
                                                        {/* 红点 */}
                                                        {!message.isOwn && !voiceReadMap[message.id] && <span className={style.voiceUnreadDot}></span>}
                                                        {/* 显示录音时长 */}
                                                        <span className={style.voiceDuration}>{message.duration || 1}″</span>
                                                        <span className={style.voiceIcon}>
                                                            <svg width="22" height="22" viewBox="0 0 22 22"><path d="M6 11a5 5 0 0 1 5-5v2a3 3 0 0 0-3 3h-2zm5-5v2a5 5 0 0 1 5 5h2a7 7 0 0 0-7-7zm0 10v2a7 7 0 0 0 7-7h-2a5 5 0 0 1-5 5z" fill="#222"/></svg>
                                                        </span>
                                                        {playingAudioId === message.id && <span className={style.voicePlayingBar}></span>}
                                                    </div>
                                                    <span
                                                        style={{
                                                            color: '#06c05f',
                                                            fontSize: 17,
                                                            fontWeight: 500,
                                                            cursor: 'pointer',
                                                            userSelect: 'none',
                                                            padding: '0 6px',
                                                            lineHeight: '32px',
                                                            borderRadius: 6,
                                                            transition: 'background 0.2s',
                                                            marginLeft: message.isOwn ? 0 : 4,
                                                            marginRight: message.isOwn ? 4 : 0,
                                                            background: 'transparent',
                                                            whiteSpace: 'nowrap',
                                                        }}
                                                        onMouseOver={e => e.currentTarget.style.background = '#e8f8ee'}
                                                        onMouseOut={e => e.currentTarget.style.background = 'transparent'}
                                                        onClick={async (e) => {
                                                            e.stopPropagation();
                                                            if (voiceTextMap[message.id]) {
                                                                setVoiceTextShowMap(v => ({ ...v, [message.id]: !v[message.id] }));
                                                                return;
                                                            }
                                                            if (voiceTranscribing[message.id]) return;
                                                            setVoiceTranscribing(v => ({ ...v, [message.id]: true }));
                                                            // 假数据模拟转写，实际应调用API
                                                            setTimeout(() => {
                                                                setVoiceTextMap(v => ({ ...v, [message.id]: '（这里是转写的文字内容，实际应调用API）' }));
                                                                setVoiceTranscribing(v => ({ ...v, [message.id]: false }));
                                                                setVoiceTextShowMap(v => ({ ...v, [message.id]: true }));
                                                            }, 1200);
                                                        }}
                                                    >
                                                        {voiceTextMap[message.id] ? (voiceTextShowMap[message.id] ? '收起转文字' : '转文字') : (voiceTranscribing[message.id] ? '转写中...' : '转文字')}
                                                    </span>
                                                </div>
                                            ) : message.type === 'transfer' ? (
                                                <TransferCard message={message} onClick={() => !isSelectMode && navigate('/ttransfer', { state: { ...message } })} />
                                            ) : message.type === 'image' ? (
                                                <div className={style.messageContent}>
                                                    <img
                                                        src={message.fileUrl}
                                                        alt="img"
                                                        style={{ maxWidth: 120, maxHeight: 120, borderRadius: 8, cursor: isSelectMode ? 'default' : 'pointer' }}
                                                        onClick={() => {
                                                            if (isSelectMode) return;
                                                            const imgs = messages.filter(m => m.type === 'image').map(m => m.fileUrl);
                                                            setPreviewImages(imgs);
                                                            setPreviewIndex(imgs.indexOf(message.fileUrl));
                                                        }}
                                                    />
                                                </div>
                                            ) : message.type === 'video' ? (
                                                <div className={style.messageContent}>
                                                    <video src={message.fileUrl} controls style={{ maxWidth: 180, maxHeight: 180, borderRadius: 8 }} />
                                                </div>
                                            ) : message.type === 'emoji' ? (
                                                <div className={style.messageContent}>
                                                    <span style={{ fontSize: 24 }}>{message.text}</span>
                                                </div>
                                            ) : (
                                                <div className={style.messageContent}>
                                                    <div className={style.messageText}>{message.text}</div>
                                                </div>
                                            )}
                                            {message.isOwn && <span className={style.bubbleArrowRight}></span>}
                                        </div>
                                    </div>
                                    {/* 右侧头像 */}
                                    {message.isOwn && (
                                        <img src="/微信头像.jpg" alt="avatar" className={style.avatar} />
                                    )}
                                </div>
                            </div>
                        ))}
                        {/* 选择模式下的底部操作栏 */}
                        {isSelectMode && (
                            <div
                                style={{
                                    position: 'fixed',
                                    bottom: 0,
                                    left: 0,
                                    right: 0,
                                    background: '#fff',
                                    borderTop: '1px solid #eee',
                                    padding: '10px 16px',
                                    display: 'flex',
                                    alignItems: 'center',
                                    justifyContent: 'space-between',
                                    zIndex: 1000,
                                    boxShadow: '0 -2px 8px rgba(0,0,0,0.1)'
                                }}
                            >
                                <div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
                                    <button
                                        style={{
                                            background: 'none',
                                            border: 'none',
                                            color: '#06c05f',
                                            fontSize: 16,
                                            cursor: 'pointer',
                                            padding: '8px 12px',
                                            borderRadius: 6
                                        }}
                                        onClick={selectedMessages.length === messages.length ? deselectAllMessages : selectAllMessages}
                                    >
                                        {selectedMessages.length === messages.length ? '取消全选' : '全选'}
                                    </button>
                                    <span style={{ color: '#666', fontSize: 14 }}>
                                        已选择 {selectedMessages.length} 条
                                    </span>
                                </div>
                                <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
                                    <button
                                        style={{
                                            background: 'none',
                                            border: '1px solid #ddd',
                                            color: '#666',
                                            fontSize: 16,
                                            cursor: 'pointer',
                                            padding: '8px 16px',
                                            borderRadius: 6
                                        }}
                                        onClick={exitSelectMode}
                                    >
                                        取消
                                    </button>
                                    <button
                                        style={{
                                            background: selectedMessages.length > 0 ? '#ff3b30' : '#ddd',
                                            border: 'none',
                                            color: '#fff',
                                            fontSize: 16,
                                            cursor: selectedMessages.length > 0 ? 'pointer' : 'not-allowed',
                                            padding: '8px 16px',
                                            borderRadius: 6,
                                            opacity: selectedMessages.length > 0 ? 1 : 0.5
                                        }}
                                        onClick={deleteSelectedMessages}
                                        disabled={selectedMessages.length === 0}
                                    >
                                        删除选中
                                    </button>
                                </div>
                            </div>
                        )}
                    </>
                )}
                <div ref={messagesEndRef} />
            </div>

            {isSelectMode && (
                <div style={{
                    position: 'fixed',
                    bottom: 0,
                    left: 0,
                    right: 0,
                    background: '#fff',
                    borderTop: '1px solid #eee',
                    padding: '10px',
                    display: 'flex',
                    justifyContent: 'space-between',
                    alignItems: 'center',
                    zIndex: 1000,
                    boxShadow: '0 -2px 10px rgba(0,0,0,0.1)'
                }}>
                    <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
                        <button
                            style={{
                                padding: '8px 16px',
                                background: selectedMessages.length === messages.length ? '#ff3b30' : '#007aff',
                                color: 'white',
                                border: 'none',
                                borderRadius: '6px',
                                cursor: 'pointer',
                                fontSize: '14px'
                            }}
                            onClick={toggleSelectAll}
                        >
                            {selectedMessages.length === messages.length ? '取消全选' : '全选'}
                        </button>
                        <span style={{ fontSize: '14px', color: '#666' }}>
                            已选择 {selectedMessages.length} 条消息
                        </span>
                    </div>
                    <div style={{ display: 'flex', gap: '8px' }}>
                        <button
                            style={{
                                padding: '8px 16px',
                                background: '#ff3b30',
                                color: 'white',
                                border: 'none',
                                borderRadius: '6px',
                                cursor: 'pointer',
                                fontSize: '14px'
                            }}
                            onClick={deleteSelectedMessages}
                        >
                            删除选中 ({selectedMessages.length})
                        </button>
                        <button
                            style={{
                                padding: '8px 16px',
                                background: '#999',
                                color: 'white',
                                border: 'none',
                                borderRadius: '6px',
                                cursor: 'pointer',
                                fontSize: '14px'
                            }}
                            onClick={toggleSelectMode}
                        >
                            取消
                        </button>
                    </div>
                </div>
            )}

            <div className={style.inputBarWx} style={{ position: 'relative', ...(isSelectMode ? { paddingBottom: '80px' } : {}) }}>
                {isVoiceMode ? (
                    <>
                        <button
                            className={style.wxIconBtn}
                            type="button"
                            title="切换到文字输入"
                            onClick={() => setIsVoiceMode(false)}
                        >
                            <span role="img" aria-label="keyboard">⌨️</span>
                        </button>
                        <button
                            className={style.wxVoiceBtn}
                            type="button"
                            onClick={handleVoiceBtnClick}
                        >
                            {isRecording ? '结束录音' : '按住 说话'}
                        </button>
                    </>
                ) : (
                    <>
                        <button
                            className={style.wxIconBtn}
                            type="button"
                            title="语音"
                            onClick={() => setIsVoiceMode(true)}
                        >
                            <span role="img" aria-label="voice">🎤</span>
                        </button>
                        <input
                            type="text"
                            value={inputMessage}
                            onChange={(e) => setInputMessage(e.target.value)}
                            className={style.wxInput}
                            disabled={!isConnected}
                        />
                    </>
                )}
                {/* 表情按钮和面板UI */}
                <button
                    className={style.wxIconBtn}
                    type="button"
                    title="表情"
                    onClick={e => {
                      e.stopPropagation();
                      setShowEmojiPanel(v => !v);
                    }}
                    style={{ marginLeft: 4 }}
                  >
                    <span role="img" aria-label="emoji">😀</span>
                  </button>
                  {showEmojiPanel && (
                    <div
                      style={{
                        position: 'absolute',
                        left: 0,
                        right: 0,
                        bottom: '100%', // 紧贴输入区上方
                        width: '100%',
                        minWidth: 320,
                        maxWidth: 480,
                        margin: 0,
                        background: '#fff',
                        borderRadius: '18px 18px 0 0', // 只上圆角
                        boxShadow: '0 2px 16px #0001',
                        zIndex: 1200,
                        padding: '10px 0 0 0',
                        minHeight: 160,
                        maxHeight: 340,
                        overflowY: 'auto',
                        transition: 'all 0.2s cubic-bezier(.34,1.56,.64,1)'
                      }}
                      onClick={e => e.stopPropagation()}
                    >
                      {/* 顶部分组切换栏 */}
                      <div style={{ display: 'flex', alignItems: 'center', borderBottom: '1px solid #eee', padding: '0 10px 6px 10px', marginBottom: 8 }}>
                        {EMOJI_GROUPS.map(group => (
                          <div
                            key={group.key}
                            style={{
                              marginRight: 12,
                              cursor: 'pointer',
                              borderBottom: activeEmojiGroup === group.key ? '2px solid #06c05f' : '2px solid transparent',
                              padding: '2px 0',
                              display: 'flex', flexDirection: 'column', alignItems: 'center',
                              fontSize: 12, color: activeEmojiGroup === group.key ? '#06c05f' : '#888', fontWeight: 500
                            }}
                            onClick={() => setActiveEmojiGroup(group.key)}
                          >
                            <img src={group.images[0]} alt={group.name} style={{ width: 32, height: 32, borderRadius: 6, marginBottom: 2, border: activeEmojiGroup === group.key ? '2px solid #06c05f' : '2px solid #eee', background: '#f6f6f6' }} />
                            {group.name}
                          </div>
                        ))}
                      </div>
                      {/* 当前分组内容区 */}
                      <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', padding: '0 12px 12px 12px' }}>
                        {EMOJI_GROUPS.find(g => g.key === activeEmojiGroup).images.map(url => (
                          <img key={url} src={url} alt="emoji" style={{ width: 48, height: 48, borderRadius: 8, cursor: 'pointer', background: '#f6f6f6' }} onClick={() => sendEmojiImage(url)} />
                        ))}
                      </div>
                      {/* 关闭按钮 */}
                      <button style={{ position: 'absolute', right: 12, bottom: 12, background: '#fff', border: 'none', borderRadius: '50%', width: 32, height: 32, boxShadow: '0 2px 8px #eee', cursor: 'pointer', fontSize: 18 }} onClick={() => setShowEmojiPanel(false)}>×</button>
                    </div>
                  )}
                <button
                    className={inputMessage.trim() ? style.sendBtn : style.wxIconBtn}
                    tabIndex={-1}
                    type="button"
                    title={inputMessage.trim() ? "发送" : "更多"}
                    onClick={inputMessage.trim() ? sendMessage : () => setShowPlusPanel(v => !v)}
                    disabled={!isConnected || (inputMessage.trim() && !inputMessage)}
                >
                    {inputMessage.trim() ? (
                        <span className={style.sendBtnText}>发送</span>
                    ) : (
                        <span role="img" aria-label="plus">➕</span>
                    )}
                </button>
            </div>

            {showPlusPanel && (
                <div className={style.plusPanelMask} onClick={() => setShowPlusPanel(false)}>
                    <div className={style.plusPanel} onClick={e => e.stopPropagation()}>
                        <div className={style.plusPanelRow}>
                            <div className={style.plusPanelItem} onClick={openImagePicker}>
                                <span className={style.plusPanelIcon}>
                                    {/* 相册 */}
                                    <svg width="32" height="32" viewBox="0 0 32 32" fill="none"><rect x="5" y="8" width="22" height="16" rx="4" fill="#fff" stroke="#111" strokeWidth="2"/><circle cx="11" cy="14" r="2" fill="#111"/><path d="M7 22l5-6 4 5 5-7 4 8" stroke="#111" strokeWidth="2" strokeLinejoin="round" fill="none"/></svg>
                                </span>
                                <div className={style.plusPanelText}>相册</div>
                            </div>
                            <input
                                type="file"
                                ref={fileInputRef}
                                style={{ display: 'none' }}
                                accept="image/*,video/*"
                                multiple
                                onChange={e => {
                                    setSelectedFiles(Array.from(e.target.files));
                                    setShowPlusPanel(false);
                                }}
                            />
                            <div className={style.plusPanelItem}>
                                <span className={style.plusPanelIcon}>
                                    {/* 拍摄 */}
                                    <svg width="32" height="32" viewBox="0 0 32 32" fill="none"><rect x="7" y="11" width="18" height="12" rx="3" fill="#fff" stroke="#111" strokeWidth="2"/><circle cx="16" cy="17" r="4" fill="#111"/><rect x="12" y="7" width="8" height="4" rx="2" fill="#111"/></svg>
                                </span>
                                <div className={style.plusPanelText}>拍摄</div>
                            </div>
                            <div className={style.plusPanelItem}>
                                <span className={style.plusPanelIcon}
                                onClick={() => setShowCallSheet(true)}
                                >
                                    {/* 视频通话 */}
                                    <svg width="32" height="32" viewBox="0 0 32 32" fill="none"><rect x="6" y="10" width="14" height="12" rx="3" fill="#fff" stroke="#111" strokeWidth="2"/><rect x="22" y="13" width="4" height="6" rx="1" fill="#111"/></svg>
                                </span>
                                <div className={style.plusPanelText}>视频通话</div>
                            </div>
                            <div className={style.plusPanelItem}>
                                <span className={style.plusPanelIcon}>
                                    {/* 位置 */}
                                    <svg width="32" height="32" viewBox="0 0 32 32" fill="none"><path d="M16 28s8-8.5 8-14A8 8 0 1 0 8 14c0 5.5 8 14 8 14z" stroke="#111" strokeWidth="2" fill="#fff"/><circle cx="16" cy="14" r="3" fill="#111"/></svg>
                                </span>
                                <div className={style.plusPanelText}>更换背景</div>
                            </div>
                        </div>
                        <div className={style.plusPanelRow}>
                            <div className={style.plusPanelItem}>
                                <span className={style.plusPanelIcon}>
                                    {/* 红包 */}
                                    <svg width="32" height="32" viewBox="0 0 32 32" fill="none"><rect x="7" y="8" width="18" height="16" rx="4" fill="#fff" stroke="#111" strokeWidth="2"/><path d="M7 12h18" stroke="#111" strokeWidth="2"/><circle cx="16" cy="18" r="3" fill="#111"/></svg>
                                </span>
                                <div className={style.plusPanelText}>红包</div>
                            </div>
                            <div className={style.plusPanelItem}>
                                <span className={style.plusPanelIcon}>
                                    {/* 礼物 */}
                                    <svg width="32" height="32" viewBox="0 0 32 32" fill="none"><rect x="7" y="12" width="18" height="12" rx="3" fill="#fff" stroke="#111" strokeWidth="2"/><path d="M7 18h18" stroke="#111" strokeWidth="2"/><rect x="13" y="7" width="6" height="6" rx="3" fill="#fff" stroke="#111" strokeWidth="2"/><path d="M16 12v12" stroke="#111" strokeWidth="2"/></svg>
                                </span>
                                <div className={style.plusPanelText}>礼物</div>
                            </div>
                            <div className={style.plusPanelItem} onClick={() => navigate('/ttransfer', { state: { ws, userId, userName: '用户2', targetUserId, targetUserName: '好友', targetUserAvatar: '/个人头像.png' } })} style={{cursor:'pointer'}}>
                                <span className={style.plusPanelIcon}>
                                    {/* 转账 */}
                                    <svg width="32" height="32" viewBox="0 0 32 32" fill="none"><rect x="7" y="12" width="18" height="8" rx="3" fill="#fff" stroke="#111" strokeWidth="2"/><path d="M13 16h6" stroke="#111" strokeWidth="2"/><path d="M19 14l3 2-3 2" stroke="#111" strokeWidth="2" strokeLinejoin="round"/></svg>
                                </span>
                                <div className={style.plusPanelText}>转账</div>
                            </div>
                            <div className={style.plusPanelItem}>
                                <span className={style.plusPanelIcon}>
                                    {/* 语音输入 */}
                                    <svg width="32" height="32" viewBox="0 0 32 32" fill="none"><rect x="12" y="7" width="8" height="14" rx="4" fill="#fff" stroke="#111" strokeWidth="2"/><path d="M16 21v4" stroke="#111" strokeWidth="2"/><path d="M12 25h8" stroke="#111" strokeWidth="2"/></svg>
                                </span>
                                <div className={style.plusPanelText}>语音输入</div>
                            </div>
                        </div>
                        <div className={style.plusPanelDots}>
                            <span className={style.dotActive}></span>
                            <span className={style.dot}></span>
                        </div>
                    </div>
                </div>
            )}

            {isRecording && (
                <div className={style.recordMask}>
                    <div className={style.recordModal}>
                        {/* 错误提示 */}
                        {recordError && <div style={{color:'#ff3b30',marginBottom:8,fontSize:14}}>{recordError}</div>}
                        <div className={style.recordMicWrap}>
                            <svg className={style.recordMic} width="32" height="32" viewBox="0 0 32 32"><rect x="10" y="4" width="12" height="16" rx="6" fill="#fff" stroke="#06c05f" strokeWidth="2"/><rect x="14" y="20" width="4" height="6" rx="2" fill="#06c05f"/><rect x="8" y="26" width="16" height="3" rx="1.5" fill="#06c05f"/></svg>
                            <div className={style.recordVolumeBar}>
                                {[...Array(7)].map((_, i) => (
                                    <div
                                        key={i}
                                        className={style.recordVolumeCol}
                                        style={{
                                            height: `${10 + (i + 1) * 6}px`,
                                            opacity: i < volumeLevel ? 1 : 0.25
                                        }}
                                    />
                                ))}
                            </div>
                        </div>
                        <div className={style.recordText}>松开 结束</div>
                        <div className={style.recordTime}>{recordTime}"</div>
                    </div>
                </div>
            )}

            {selectedFiles.length > 0 && (
                <div style={{ display: 'flex', gap: 8, padding: 10, background: '#fff', borderTop: '1px solid #eee', position: 'fixed', bottom: 0, left: 0, right: 0, zIndex: 1000 }}>
                    {selectedFiles.map((file, idx) => {
                        const url = URL.createObjectURL(file);
                        if (file.type.startsWith('image/')) {
                            return <img key={idx} src={url} alt="preview" style={{ width: 60, height: 60, objectFit: 'cover', borderRadius: 6 }} />;
                        } else if (file.type.startsWith('video/')) {
                            return <video key={idx} src={url} controls style={{ width: 60, height: 60, objectFit: 'cover', borderRadius: 6 }} />;
                        }
                        return null;
                    })}
                    <button style={{ marginLeft: 12 }} onClick={async () => {
                        for (const file of selectedFiles) {
                            const url = URL.createObjectURL(file);
                            let msg = null;
                            if (file.type.startsWith('image/')) {
                                msg = {
                                    id: Date.now() + Math.random(),
                                    type: 'image',
                                    sender: userId,
                                    isOwn: true,
                                    fileName: file.name,
                                    fileUrl: url,
                                    timestamp: new Date().toLocaleTimeString()
                                };
                            } else if (file.type.startsWith('video/')) {
                                msg = {
                                    id: Date.now() + Math.random(),
                                    type: 'video',
                                    sender: userId,
                                    isOwn: true,
                                    fileName: file.name,
                                    fileUrl: url,
                                    timestamp: new Date().toLocaleTimeString()
                                };
                            }
                            if (msg) setMessages(prev => [...prev, msg]);
                        }
                        setSelectedFiles([]);
                    }}>发送</button>
                    <button style={{ marginLeft: 6 }} onClick={() => setSelectedFiles([])}>取消</button>
                </div>
            )}

            {showImagePicker && (
              <div
                style={{
                  position: 'fixed', left: 0, right: 0, top: 0, bottom: 0,
                  background: '#000', zIndex: 2000,
                  display: 'flex', flexDirection: 'column', justifyContent: 'flex-end', padding: 0, margin: 0
                }}
                onClick={closeImagePicker}
              >
                <div
                  style={{
                    width: '100vw',
                    height: '100vh',
                    background: '#000',
                    borderTopLeftRadius: 16,
                    borderTopRightRadius: 16,
                    boxShadow: '0 -2px 16px rgba(0,0,0,0.08)',
                    transform: imagePickerVisible ? 'translateY(0)' : 'translateY(100%)',
                    transition: 'transform 0.3s cubic-bezier(.34,1.56,.64,1)',
                    overflow: 'hidden',
                    position: 'relative',
                    display: 'flex', flexDirection: 'column', justifyContent: 'space-between',
                    padding: 0, margin: 0
                  }}
                  onClick={e => e.stopPropagation()}
                >
                  {/* 顶部微信风格头部 */}
                  <div style={{
                    height: 48,
                    background: '#333',
                    display: 'flex',
                    alignItems: 'center',
                    justifyContent: 'center',
                    position: 'relative',
                  }}>

                    {/* 关闭按钮 */}
                    <span
                      style={{
                        position: 'absolute',
                        left: 16,
                        top: 0,
                        height: '100%',
                        display: 'flex',
                        alignItems: 'center',
                        color: '#fff',
                        fontSize: 28,
                        cursor: 'pointer',
                        fontWeight: 'bold',
                        zIndex: 2,
                      }}
                      onClick={closeImagePicker}
                    >
                      ×
                    </span>
                    {/* 中间标签 */}
                    <span style={{
                      background: 'rgba(0,0,0,0.25)',
                      color: '#fff',
                      borderRadius: 20,
                      padding: '4px 18px 4px 14px',
                      fontSize: 18,
                      fontWeight: 500,
                      display: 'flex',
                      alignItems: 'center',
                    }}>
                      图片和视频
                      <svg style={{marginLeft: 4}} width="22" height="22" viewBox="0 0 22 22"><circle cx="11" cy="11" r="11" fill="#888"/><path d="M7 9l4 4 4-4" stroke="#fff" strokeWidth="2" fill="none"/></svg>
                    </span>
                  </div>
                  {/* 图片网格 */}
                  <div style={{ flex: 1, overflowY: 'auto', padding: 0, margin: 0 }}>
                    <div style={{
                      display: 'grid',
                      gridTemplateColumns: 'repeat(4, 1fr)',
                      gap: '0px',
                      width: '100%',
                      height: '100%',
                      margin: 0,
                      padding: 0
                    }}>
                      {publicImages.map((img, idx) => {
                        const selectedIdx = selectedPublicImages.indexOf(img);
                        return (
                          <div
                            key={idx}
                            style={{
                              position: 'relative',
                              width: '100%',
                              aspectRatio: '1/1',
                              background: '#eee',
                              border: selectedIdx !== -1 ? '3px solid #06c05f' : '2px solid #000',
                              boxSizing: 'border-box',
                              cursor: 'pointer',
                              overflow: 'hidden',
                              margin: 0,
                              padding: 0
                            }}
                            onClick={() => {
                              setSelectedPublicImages(prev =>
                                prev.includes(img)
                                  ? prev.filter(i => i !== img)
                                  : [...prev, img]
                              );
                            }}
                          >
                            <img
                              src={img}
                              alt=""
                              style={{
                                width: '100%',
                                height: '100%',
                                objectFit: 'cover',
                                display: 'block',
                                margin: 0,
                                padding: 0
                              }}
                            />
                            {selectedIdx !== -1 && (
                              <div style={{
                                position: 'absolute',
                                top: 6,
                                right: 6,
                                width: 22,
                                height: 22,
                                background: '#06c05f',
                                color: '#fff',
                                borderRadius: '50%',
                                display: 'flex',
                                alignItems: 'center',
                                justifyContent: 'center',
                                fontSize: 14,
                                fontWeight: 'bold',
                                zIndex: 2,
                                boxShadow: '0 1px 4px #aaa',
                              }}>{selectedIdx + 1}</div>
                            )}
                          </div>
                        );
                      })}
                    </div>
                  </div>
                  {/* 微信风格底部操作栏 */}
                  <div style={{
                    background: '#333',
                    color: '#fff',
                    display: 'flex',
                    alignItems: 'center',
                    justifyContent: 'space-between',
                    height: 48,
                    padding: '0 18px',
                    fontSize: 18,
                    borderTop: '1px solid #222',
                  }}>
                    <span style={{color: '#fff', opacity: 0.95, fontSize: 16, fontWeight: 500}}>预览</span>
                    <span style={{display: 'flex', alignItems: 'center', color: '#fff', fontSize: 16}}>
                      <span style={{
                        width: 22, height: 22, border: '2px solid #fff', borderRadius: '50%', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', marginRight: 6
                      }}>
                        {false && <span style={{width: 12, height: 12, background: '#06c05f', borderRadius: '50%', display: 'block'}}></span>}
                      </span>
                      原图
                    </span>
                    <button
                      style={{
                        background: selectedPublicImages.length === 0 ? '#444' : '#06c05f',
                        color: '#fff',
                        border: 'none',
                        borderRadius: 8,
                        padding: '6px 22px',
                        fontSize: 18,
                        fontWeight: 'bold',
                        cursor: selectedPublicImages.length === 0 ? 'not-allowed' : 'pointer',
                        opacity: selectedPublicImages.length === 0 ? 0.5 : 1,
                        transition: 'background 0.2s',
                      }}
                      disabled={selectedPublicImages.length === 0}
                      onClick={() => {
                        selectedPublicImages.forEach(img => {
                          if (ws && ws.readyState === 1) {
                            ws.send(JSON.stringify({
                              type: 'image',
                              fileUrl: img,
                              senderId: userId,
                              receiverId: targetUserId,
                              timestamp: new Date().toISOString()
                            }));
                          }
                        });
                                                setMessages(prev => [
                            ...prev,
                            ...selectedPublicImages.map(img => ({
                                id: Date.now() + Math.random(),
                                type: 'image',
                                sender: userId,
                                isOwn: true,
                                fileUrl: img,
                                timestamp: new Date().toLocaleTimeString()
                            }))
                        ]);
                        closeImagePicker();
                        setSelectedPublicImages([]);
                      }}
                    >
                      发送{selectedPublicImages.length > 0 ? `(${selectedPublicImages.length})` : ''}
                    </button>
                  </div>
                </div>
              </div>
            )}
            {previewImages.length > 0 && (
              <PreviewModal
                images={previewImages}
                index={previewIndex}
                setIndex={setPreviewIndex}
                onClose={() => setPreviewImages([])}
                tip={previewTip}
                setTip={setPreviewTip}
                handleCollectEmoji={handleCollectEmoji}
                favoriteEmojis={favoriteEmojis}
              />
            )}
            {showCallSheet && (
              <div className={style.actionSheetMask} onClick={() => setShowCallSheet(false)}>
                <div className={style.actionSheet} onClick={e => e.stopPropagation()}>
                  <div className={style.actionSheetItem} tabIndex={0}>
                    <span className={style.iconVideo} /> 视频通话
                  </div>
                  <div className={style.actionSheetItem} tabIndex={0}>
                    <span className={style.iconPhone} /> 语音通话
                  </div>
                  <div className={style.actionSheetCancel} tabIndex={0} onClick={() => setShowCallSheet(false)}>
                    取消
                  </div>
                </div>
              </div>
            )}
        </div>
    );
}function PreviewModal({ images, index, setIndex, onClose, tip, setTip, handleCollectEmoji, favoriteEmojis }) {
  // 键盘切换
  React.useEffect(() => {
    if (images.length > 0) {
      const handleKeyDown = (e) => {
        if (e.key === 'ArrowLeft') {
          if (index === 0) {
            setTip('已经是第一张');
            if (window.__previewTipTimer) clearTimeout(window.__previewTipTimer);
            window.__previewTipTimer = setTimeout(() => setTip(''), 2000);
          } else {
            setIndex(i => i - 1);
          }
        } else if (e.key === 'ArrowRight') {
          if (index === images.length - 1) {
            setTip('已经是最后一张');
            if (window.__previewTipTimer) clearTimeout(window.__previewTipTimer);
            window.__previewTipTimer = setTimeout(() => setTip(''), 2000);
          } else {
            setIndex(i => i + 1);
          }
        } else if (e.key === 'Escape') {
          onClose();
        }
      };
      window.addEventListener('keydown', handleKeyDown);
      return () => window.removeEventListener('keydown', handleKeyDown);
    }
  }, [images, index, setIndex, setTip, onClose]);
  // 清理定时器
  React.useEffect(() => () => { if (window.__previewTipTimer) clearTimeout(window.__previewTipTimer); }, []);
  return (
    <div
      style={{
        position: 'fixed', left: 0, top: 0, right: 0, bottom: 0, zIndex: 3000,
        background: 'rgba(0,0,0,0.85)', display: 'flex', alignItems: 'center', justifyContent: 'center'
      }}
      onClick={onClose}
    >
      <div style={{ position: 'relative', display: 'flex', alignItems: 'center' }} onClick={e => e.stopPropagation()}>
        {/* 上一张 */}
        <button
          style={{
            position: 'absolute', left: 16, top: '50%', transform: 'translateY(-50%)',
            width: 60, height: 60, borderRadius: '50%', background: 'rgba(0,0,0,0.65)',
            border: 'none', display: 'flex', alignItems: 'center', justifyContent: 'center',
            color: '#fff', fontSize: 38, cursor: 'pointer', zIndex: 2, boxShadow: '0 4px 16px #0006',
            transition: 'background 0.2s, box-shadow 0.2s',
          }}
          onMouseOver={e => e.currentTarget.style.background = 'rgba(0,0,0,0.85)'}
          onMouseOut={e => e.currentTarget.style.background = 'rgba(0,0,0,0.65)'}
          onClick={e => {
            e.stopPropagation();
            if (index === 0) {
              setTip('已经是第一张');
              if (window.__previewTipTimer) clearTimeout(window.__previewTipTimer);
              window.__previewTipTimer = setTimeout(() => setTip(''), 2000);
            } else {
              setIndex(i => i - 1);
            }
          }}
          aria-label="上一张"
        >
          <svg width="36" height="36" viewBox="0 0 36 36"><circle cx="18" cy="18" r="18" fill="none"/><polyline points="23,9 13,18 23,27" fill="none" stroke="#fff" strokeWidth="4" strokeLinecap="round" strokeLinejoin="round"/></svg>
        </button>
        {/* 图片 */}
        <img src={images[index]} alt="" style={{ maxWidth: '90vw', maxHeight: '80vh', borderRadius: 10 }} />
        {/* 下一张 */}
        <button
          style={{
            position: 'absolute', right: 16, top: '50%', transform: 'translateY(-50%)',
            width: 60, height: 60, borderRadius: '50%', background: 'rgba(0,0,0,0.65)',
            border: 'none', display: 'flex', alignItems: 'center', justifyContent: 'center',
            color: '#fff', fontSize: 38, cursor: 'pointer', zIndex: 2, boxShadow: '0 4px 16px #0006',
            transition: 'background 0.2s, box-shadow 0.2s',
          }}
          onMouseOver={e => e.currentTarget.style.background = 'rgba(0,0,0,0.85)'}
          onMouseOut={e => e.currentTarget.style.background = 'rgba(0,0,0,0.65)'}
          onClick={e => {
            e.stopPropagation();
            if (index === images.length - 1) {
              setTip('已经是最后一张');
              if (window.__previewTipTimer) clearTimeout(window.__previewTipTimer);
              window.__previewTipTimer = setTimeout(() => setTip(''), 2000);
            } else {
              setIndex(i => i + 1);
            }
          }}
          aria-label="下一张"
        >
          <svg width="36" height="36" viewBox="0 0 36 36"><circle cx="18" cy="18" r="18" fill="none"/><polyline points="13,9 23,18 13,27" fill="none" stroke="#fff" strokeWidth="4" strokeLinecap="round" strokeLinejoin="round"/></svg>
        </button>
        {/* 关闭按钮 */}
        <button
          style={{ position: 'absolute', top: -50, right: 0, fontSize: 22, color: '#fff', background: 'rgba(0,0,0,0.4)', border: 'none', borderRadius: 8, padding: '6px 18px', cursor: 'pointer' }}
          onClick={e => { e.stopPropagation(); onClose(); }}
        >关闭</button>
        {/* 收藏按钮 */}
        {images[index] && !images[index].startsWith('data:') && (
          <button
            style={{
              position: 'absolute',
              top: -50,
              right: 80,
              fontSize: 16,
              color: '#fff',
              background: 'rgba(0,0,0,0.4)',
              border: 'none',
              borderRadius: 8,
              padding: '6px 18px',
              cursor: 'pointer',
              display: 'flex',
              alignItems: 'center',
              gap: 6
            }}
            onClick={e => {
              e.stopPropagation();
              if (handleCollectEmoji) {
                handleCollectEmoji(images[index]);
              }
            }}
          >
            {favoriteEmojis && favoriteEmojis.includes(images[index]) ? '已收藏' : '收藏'}
          </button>
        )}
        {/* 提示 */}
        {tip && (
          <div style={{
            position: 'fixed', left: '50%', bottom: 60, transform: 'translateX(-50%)',
            background: 'rgba(0,0,0,0.8)', color: '#fff', padding: '8px 16px', borderRadius: 20,
            fontSize: 14, zIndex: 3001
          }}>
            {tip}
          </div>
        )}
      </div>
    </div>
  );
}

